package com.doyens.gmall.cart.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.doyens.gmall.cart.mapper.CartInfoMapper;
import com.doyens.gmall.common.constant.RedisConst;
import com.doyens.gmall.common.util.DateUtil;
import com.doyens.gmall.model.cart.CartInfo;
import com.doyens.gmall.model.product.SkuInfo;
import com.doyens.gmall.product.client.ProductFeignClient;
import com.doyens.gmall.cart.service.CartService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * Classname:CartService
 * PackageName:com.doyens.gmall.service.impl
 *
 * @Author:uyijk
 * @Create:2023/8/8 11:25
 * @Version: 1.0
 */
@Service
public class CartServiceImpl implements CartService {
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private CartInfoMapper cartInfoMapper;
    @Autowired
    private ProductFeignClient productFeignClient;
    private CartAsyncServiceImpl cartAsyncService;

    @Override
    public void addToCart(Long skuId, String userId, Integer skuNum) {
        //购物车中有这个商品，修改数量,
        //查询购物车中是否有，从redis中查，需要保证redis跟数据库是实时同步的
        HashOperations hashOperations = redisTemplate.opsForHash();
        String cartKey = getCartKey(userId);
        //判断redis中是否有这个用户的购物车缓存
        if(!redisTemplate.hasKey(cartKey)){
            //沒有购物车，加载缓存
            this.loadCartCache(userId);
        }

        //redis有缓存,再判断购物车中有没有这个要添加的商品
        CartInfo  cartInfo = (CartInfo) hashOperations.get(cartKey, skuId.toString());
        if (cartInfo==null){
            //购物车没有这个商品，添加数据库
            cartInfo = new CartInfo();
            cartInfo.setUserId(userId);
            cartInfo.setSkuId(skuId);
            cartInfo.setSkuNum(skuNum);
            //商品信息，需要远程调用service-product查询
            SkuInfo skuInfo = productFeignClient.getSkuInfo(skuId);
            cartInfo.setSkuName(skuInfo.getSkuName());
            cartInfo.setImgUrl(skuInfo.getSkuDefaultImg());
            //从数据库查询最新的价格
            BigDecimal skuPrice = productFeignClient.getSkuPrice(skuId);
            //购物车商品的实时价格
            cartInfo.setSkuPrice(skuPrice);
            //添加购物车时候的价格
            cartInfo.setCartPrice(skuPrice);
            //手动设置添加到购物车的时间，更新时间
            cartInfo.setCreateTime(new Timestamp(System.currentTimeMillis()));
            cartInfo.setUpdateTime(new Timestamp(System.currentTimeMillis()));
            cartInfo.setIsChecked(1);
            cartAsyncService.addToCart(cartInfo);
        }else{
            //购物车有这个商品，修改数量
            cartInfo.setSkuNum(cartInfo.getSkuNum()+skuNum);
            //修改提交到数据库
            cartInfoMapper.updateById(cartInfo);
        }
        //更新redis
        hashOperations.put(cartKey,skuId.toString(),cartInfo);
        this.setCartKeyExpire(cartKey);

    }

    @Override
    public List<CartInfo> getCartList(String userId, String userTempId) {

        if(StringUtils.isEmpty(userId)){
            //未登录,直接查询购物车信息返回
            return this.getCartList(userTempId);
        }else{
            //已登录
            List<CartInfo> cartInfoLoginList = this.getCartList(userId);
            //需要查询未登录的购物车
            List<CartInfo> cartInfoNoLoginList = this.getCartList(userTempId);

            if(CollectionUtils.isEmpty(cartInfoNoLoginList)){
                //没有临时用户的数据
                return cartInfoLoginList;
            }

           return this.mergeCartInfoList(cartInfoLoginList,cartInfoNoLoginList,userId,userTempId);
        }
    }

    @Override
    public void checkCart(String userId, Long skuId, Integer isChecked) {
        //修改数据库
        CartInfo cartInfo = new CartInfo();
        cartInfo.setIsChecked(isChecked);
        LambdaQueryWrapper<CartInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CartInfo::getUserId,userId);
        queryWrapper.eq(CartInfo::getSkuId,skuId);
        cartInfoMapper.update(cartInfo,queryWrapper);
        //修改redis
        String cartKey = getCartKey(userId);
        HashOperations hashOperations = redisTemplate.opsForHash();
        if(hashOperations.hasKey(cartKey,skuId.toString())){
            CartInfo cartInfo1 = (CartInfo) hashOperations.get(cartKey, skuId.toString());
            cartInfo1.setIsChecked(isChecked);
            hashOperations.put(cartKey,skuId.toString(),cartInfo1);
            setCartKeyExpire(cartKey);
        }
    }

    @Override
    public void deleteCart(String userId, Long skuId) {
        //删除数据库
        cartAsyncService.deleteByUserIdAndSkuId(userId,skuId);
        //删除redis
        HashOperations hashOperations = redisTemplate.opsForHash();
        String cartKey = getCartKey(userId);
        if(hashOperations.hasKey(cartKey,skuId.toString())){
            hashOperations.delete(cartKey,skuId.toString());
        }
    }

    // 设置过期时间
    private void setCartKeyExpire(String cartKey) {
        redisTemplate.expire(cartKey, RedisConst.USER_CART_EXPIRE, TimeUnit.SECONDS);
    }


    //删除临时用户的redis
    private void delteRedisCartList(String userTempId){
        String cartKey = getCartKey(userTempId);
        redisTemplate.delete(cartKey);
    }

    //删除临时用户的数据库
    private void delteDBCartList(String userTempId){
        cartAsyncService.deleteByUserId(userTempId);
    }

    /**
     * 合并购物车
     * @param cartInfoLoginList 登录的购物车数据
     * @param cartInfoNoLoginList 未登录的购物车数据，不可能为空
     * @return
     */

    private List<CartInfo> mergeCartInfoList(List<CartInfo> cartInfoLoginList, List<CartInfo> cartInfoNoLoginList,String userId,String userTempId) {
        //登录后的购物车可能为空
        if(CollectionUtils.isEmpty(cartInfoLoginList)){
            //修改未登录的购物车信息的userId为登录后的就行
            cartInfoNoLoginList.forEach(cartInfo -> {
                cartInfo.setUserId(userId);
                cartInfoMapper.updateById(cartInfo);
            });
            //删除redis
            delteRedisCartList(userTempId);
            return this.loadCartCache(userId);
        }

        //未登录的、已登录的购物车都有数据
        Map<String, CartInfo> cartInfoMap = cartInfoLoginList.stream().collect(Collectors.toMap(new Function<CartInfo, String>() {
            @Override
            public String apply(CartInfo cartInfo) {
                return cartInfo.getSkuId().toString();
            }
        }, Function.identity()));
        cartInfoNoLoginList.forEach(cartInfo -> {
            if(cartInfoMap.containsKey(cartInfo.getSkuId())){
                //有重复的商品，修改数量
                CartInfo cartInfo1 = cartInfoMap.get(cartInfo.getSkuId());
                cartInfo1.setSkuNum(cartInfo1.getSkuNum()+cartInfo.getSkuNum());
                cartInfoMap.put(cartInfo.getSkuId().toString(),cartInfo1);
                //同时修改数据库
               cartAsyncService.updateCartInfo(cartInfo1);
            }else{
                cartInfoMap.put(cartInfo.getSkuId().toString(),cartInfo);
                cartInfo.setUserId(userId);
                //同时修改数据库
                cartAsyncService.updateCartInfo(cartInfo);
            }
        });
        //删除临时用户的购物车数据
        this.delteDBCartList(userTempId);
        //删除redis
        delteRedisCartList(userTempId);
        HashOperations hashOperations = redisTemplate.opsForHash();
        String cartKey = getCartKey(userId);
        hashOperations.putAll(cartKey,cartInfoMap);
        List<CartInfo> cartInfos = new ArrayList<>(cartInfoMap.values());
        return cartInfos;
    }

    /**
     * 根据用户id/临时id获取购物车信息
     * @param userId
     * @return
     */
    private List<CartInfo> getCartList(String userId){
        List<CartInfo> cartInfoList = new ArrayList<>();
        if(StringUtils.isEmpty(userId)){
            return cartInfoList;
        }
        String cartKey = getCartKey(userId);
        if(redisTemplate.hasKey(cartKey)) {
            //redis中有缓存
            HashOperations hashOperations = redisTemplate.opsForHash();
            cartInfoList = hashOperations.values(cartKey);
            //对list进行排序，按修改时间倒序
            cartInfoList.sort((o1,o2)->{
               return DateUtil.truncatedCompareTo(o2.getUpdateTime(),o1.getUpdateTime(),Calendar.SECOND);
            });
        }else{
            //redis无缓存
            cartInfoList= loadCartCache(userId);
        }
        return cartInfoList;
    }

    private List<CartInfo> loadCartCache(String userId) {
        //查询数据库中当前用户的所有购物车信息，放入redis缓存
        LambdaQueryWrapper<CartInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CartInfo::getUserId,userId);
        List<CartInfo> cartInfoList = cartInfoMapper.selectList(queryWrapper);
        //丢入redis中存储
        //需要把这个list转换成skuId:CartInfo的map结构
        Map<String, CartInfo> map = cartInfoList.stream().collect(Collectors.toMap(new Function<CartInfo, String>() {
            @Override
            public String apply(CartInfo cartInfo) {
                return cartInfo.getSkuId().toString();
            }
        }, Function.identity()));
        HashOperations hashOperations = redisTemplate.opsForHash();
        String cartKey = getCartKey(userId);
        hashOperations.putAll(cartKey,map);
        this.setCartKeyExpire(cartKey);
        return cartInfoList;
    }

    // 获取购物车的key
    private String getCartKey(String userId) {
        //定义key user:userId:cart
        return RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
    }

}
